Pyomo.DoE: fix trace/Cholesky initialization consistency#3867
Pyomo.DoE: fix trace/Cholesky initialization consistency#3867adowling2 wants to merge 20 commits into
Conversation
|
@smondal13 @sscini @slilonfe5 @snarasi2 @djlaky I found a small bug in how we initialize the Cholesky factorization when the FIM at the initial point needs "inertia correction". This PR fixes the initialization inconsistency. This PR also proposes an interface to allow for more advanced solver options when diagnosing initialization issues for the Pyomo.DoE (dynamic) optimization formulation. Edit: This is a work in progress right now. I am not 100% happy with the proposed changes. |
|
@sscini @blnicho @mrmundt @smondal13 @slilonfe5 This is ready for review. This PR is now narrowly targeted at fixing a Pyomo.DoE FIM initialization issue. |
|
Test failures appear to be unrelated to this PR: GAMS solvers (Windows) and NEOS solver (all) |
These failures are global. The Pyomo team mentioned that they are working on resolving the issues. |
| model.fim_inv[c, d].value = fim_inv_vals[i, j] | ||
|
|
||
| if hasattr(model, "cov_trace"): | ||
| fim_inv_np = np.linalg.inv(fim_pd) |
There was a problem hiding this comment.
Since you are making the fim PD by adding the jitter, I believe the fim_pd will probably be non-singular. But if it is singular for some edge cases, then isn't it better to use the pseudo-inverse here just to be safe?
|
|
||
|
|
||
| @unittest.skipIf( | ||
| not (numpy_available and scipy_available), |
There was a problem hiding this comment.
I think scipy is not required for the following tests. So, it may unnecessarily skip tests. Only greybox and multi-experiment initialization with LHS require scipy as far as I can remember.
| if self.objective_option == ObjectiveLib.trace: | ||
| trace_val = np.trace(np.linalg.pinv(self.get_FIM())) | ||
| model.obj_cons.egb_fim_block.outputs["A-opt"].set_value(trace_val) | ||
| elif self.objective_option == ObjectiveLib.pseudo_trace: |
There was a problem hiding this comment.
I did not see any tests for the pseudo_trace objective in test_greybox.py
Fixes # .
Summary/Motivation:
This PR
adds advanced debugging/inspection controls forfixes a trace-objective initialization inconsistency that can produce large residuals in Cholesky-related constraints at the start of the final NLP solve.pyomo.contrib.doe.DesignOfExperiments.run_doe()while preserving default behavior for typical usersThe motivating workflow showed:
inability to usemax_iter=0for final-model probing because scenario solves reused the same solver options,fim,L,fim_inv,L_inv, andcov_trace.Changes proposed in this PR:
Added an advancedrun_config(ConfigBlock/dict) argument torun_doe(model=None, results_file=None, run_config=None):scenario_solver_optionsfinal_solver_optionsfinal_solveinspection.enabledinspection.top_constraintsImplemented scoped solver option application:scenario-generation and square-initialization solves can use different options from the final optimization solve.Added optional structured residual reporting utility:reports top violated active constraints with fields:constraint_namebodylower_boundupper_boundviolationconstraint_typeAdded assemble-and-inspect path (final_solve=False) to inspect assembled NLP state without running final optimization._initialize_cholesky_from_fim()to re-synchronizeL,L_inv,fim_inv, andcov_tracefrom current FIM immediately before final solve / inspection.Updated docstrings and added advanced usage documentation + example path inreactor_example.py.test_doe_initialization.pyfor jitter behavior and FIM synchronization.Backward compatibility:
Default usage (run_doe()with norun_config) remains unchanged.Advanced functionality is available only whenrun_configis provided.Testing:
I ran:
pytest -q pyomo/contrib/doe/tests/test_doe_debug.pyResult:8 passedpytest -q pyomo/contrib/doe/tests/test_doe_solve.py -k "rooney_biegler_fd_central_solve"Result:1 passed, 17 deselectedpython3 -m unittest -q pyomo.contrib.doe.tests.test_doe_initialization3 skippedin the current interpreter because SciPy/numpy are unavailable therepython3 -m py_compile pyomo/contrib/doe/doe.py pyomo/contrib/doe/tests/test_doe_initialization.pyNew/updated tests cover:
Outstanding Tasks (before removing WIP):
Finalize proposed interface for advanced initialization diagnosticsDecide the best way to document the proposed interface. Are examples sufficient or should we build out the Pyomo documentation?Run black@adowling2 carefully reviews proposed changesWhy the strikethought?
The original version of this PR included a new interface to
run_doe()that makes debugging the initialization and, more broadly, solver failures easier. We decided that the newrun_doe()interface added too much complexity and exposed some inconsistencies in other parts of the Pyomo solver interface. (This led to a real-time Codex experiment documented in #3871.) To expedite this current PR, I decided to remove these contributions and strike through the above parts of the PR text. These contributions are still available in the git history. Thus, this current PR only contributes a targeted patch to the Pyomo FIM initialization.Legal Acknowledgement
By contributing to this software project, I have read the contribution guide and agree to the following terms and conditions for my contribution: